﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace TypeDescriptor
{
    public static class TypeExtension
    {

        public static readonly Dictionary<Type, string> _customTypeNames =
           new Dictionary<Type, string>
                {
                    {typeof (int), "int"},
                    {typeof (double), "double"},
                    {typeof (float), "float"},
                    {typeof (short), "short"},
                    {typeof (string), "string"},
                    {typeof (long), "long"},
                    {typeof (decimal), "decimal"},
                    {typeof (char), "char"},
                    {typeof (uint), "uint"},
                    {typeof (ulong), "ulong"},
                    {typeof (ushort), "ushort"},
                    {typeof (byte), "byte"},
                    {typeof (bool), "bool"},
                    {typeof (void), "void"},
                    {typeof (object), "object"},
                    {typeof (ValueType),"struct"}
                };
        /// <summary>
        /// 判断Type 是否是指定CheckingType的子类
        /// </summary>
        /// <param name="type">当前类</param>
        /// <param name="checkingType">期望的父类</param>
        /// <returns>结果</returns>
        public static bool IsBaseType(this Type type, Type checkingType)
        {
            while (type != typeof(object))
            {
                if (type != null)
                {
                    if (type == checkingType)
                    {
                        return true;
                    }
                    type = type.BaseType;
                }
            }
            return false;
        }
        /// <summary>
        /// 判断Type 是否是指定CheckingType的子类
        /// </summary>
        /// <param name="type">当前类</param>
        /// <param name="checkingType">期望的父类</param>
        /// <returns>结果</returns>
        public static bool IsBaseType(this Type type, string checkingType)
        {
            while (type != typeof(object))
            {
                if (type != null)
                {
                    if (type.FullName == checkingType)
                    {
                        return true;
                    }
                    type = type.BaseType;
                }
            }
            return false;
        }


        /// <summary>
        /// 如果当前类为基本类型，则返回其类型. 否则则常使用Func去转换type
        /// </summary>
        /// <param name="type"></param>
        /// <param name="func"></param>
        /// <exception cref="ArgumentException"></exception>
        /// <returns></returns>
        public static string ToString(this Type type, Func<Type, string> func)
        {
            string name;
            if (_customTypeNames.TryGetValue(type, out name))
                return name;
            if (type.IsEnum || type.IsValueType)
                return type.FullName;
            if (func == null)
                func = t => t != null ? t.FullName : null;
            if (type.IsArray)
            {
                name = type.GetMethod("Get").ReturnType.ToString(func);
                name += "[";
                name += (new string(',', type.GetArrayRank() - 1));
                name += "]";
                return name;

            }
            if (type.IsGenericParameter)
            {
                return type.Name;
            }
            if (type.IsByRef)
            {
                if (type.FullName != null)
                {
                    var t = Type.GetType(type.FullName.TrimEnd('&'));
                    return t.ToString(func);
                }
                throw new ArgumentException("type has no FullName Value :" + type);
            }
            if (type.IsGenericType)
            {

                string[] names = type.Name.Split('`');

                Type[] genTypes = type.GetGenericArguments();
                names[0] += "<";
                names[0] += ToString(genTypes[0], func);
                for (var i = 1; i < genTypes.Length; i++)
                {
                    names[0] += ", " + ToString(genTypes[i], func);
                }
                names[0] += ">";

                return names[0];
            }
            return func(type);
        }
    }
}
